diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index edad5f1b1b..68d5376cbd 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -77,7 +77,8 @@ HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_ses
 
 HLERequestContext::~HLERequestContext() = default;
 
-void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
+void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,
+                                           bool incoming) {
     IPC::RequestParser rp(src_cmdbuf);
     command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>());
 
@@ -94,8 +95,6 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
             rp.Skip(2, false);
         }
         if (incoming) {
-            auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
-
             // Populate the object lists with the data in the IPC request.
             for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
                 copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
@@ -189,10 +188,9 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
     rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
 }
 
-ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf,
-                                                                Process& src_process,
-                                                                HandleTable& src_table) {
-    ParseCommandBuffer(src_cmdbuf, true);
+ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
+                                                                u32_le* src_cmdbuf) {
+    ParseCommandBuffer(handle_table, src_cmdbuf, true);
     if (command_header->type == IPC::CommandType::Close) {
         // Close does not populate the rest of the IPC header
         return RESULT_SUCCESS;
@@ -207,14 +205,17 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
     return RESULT_SUCCESS;
 }
 
-ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) {
+ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
+    auto& owner_process = *thread.GetOwnerProcess();
+    auto& handle_table = owner_process.GetHandleTable();
+
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
-    Memory::ReadBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(),
+    Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
                       dst_cmdbuf.size() * sizeof(u32));
 
     // The header was already built in the internal command buffer. Attempt to parse it to verify
     // the integrity and then copy it over to the target command buffer.
-    ParseCommandBuffer(cmd_buf.data(), false);
+    ParseCommandBuffer(handle_table, cmd_buf.data(), false);
 
     // The data_size already includes the payload header, the padding and the domain header.
     std::size_t size = data_payload_offset + command_header->data_size -
@@ -236,8 +237,6 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
         ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
         ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
 
-        auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
-
         // We don't make a distinction between copy and move handles when translating since HLE
         // services don't deal with handles directly. However, the guest applications might check
         // for specific values in each of these descriptors.
@@ -268,7 +267,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
     }
 
     // Copy the translated command buffer back into the thread's command buffer area.
-    Memory::WriteBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(),
+    Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
                        dst_cmdbuf.size() * sizeof(u32));
 
     return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 894479ee03..f01491daac 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,10 +24,10 @@ class ServiceFrameworkBase;
 namespace Kernel {
 
 class Domain;
+class Event;
 class HandleTable;
 class HLERequestContext;
 class Process;
-class Event;
 
 /**
  * Interface implemented by HLE Session handlers.
@@ -126,13 +126,12 @@ public:
                                        u64 timeout, WakeupCallback&& callback,
                                        Kernel::SharedPtr<Kernel::Event> event = nullptr);
 
-    void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
-
     /// Populates this context with data from the requesting process/thread.
-    ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process,
-                                                 HandleTable& src_table);
+    ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
+                                                 u32_le* src_cmdbuf);
+
     /// Writes data from this context back to the requesting process/thread.
-    ResultCode WriteToOutgoingCommandBuffer(const Thread& thread);
+    ResultCode WriteToOutgoingCommandBuffer(Thread& thread);
 
     u32_le GetCommand() const {
         return command;
@@ -255,6 +254,8 @@ public:
     std::string Description() const;
 
 private:
+    void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
+
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
     SharedPtr<Kernel::ServerSession> server_session;
     // TODO(yuriks): Check common usage of this and optimize size accordingly
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index bd680adfe2..4b6b32dd54 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -118,7 +118,6 @@ struct KernelCore::Impl {
         process_list.clear();
         current_process = nullptr;
 
-        handle_table.Clear();
         resource_limits.fill(nullptr);
 
         thread_wakeup_callback_handle_table.Clear();
@@ -209,7 +208,6 @@ struct KernelCore::Impl {
     std::vector<SharedPtr<Process>> process_list;
     Process* current_process = nullptr;
 
-    Kernel::HandleTable handle_table;
     std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
 
     /// The event type of the generic timer callback event
@@ -241,14 +239,6 @@ void KernelCore::Shutdown() {
     impl->Shutdown();
 }
 
-Kernel::HandleTable& KernelCore::HandleTable() {
-    return impl->handle_table;
-}
-
-const Kernel::HandleTable& KernelCore::HandleTable() const {
-    return impl->handle_table;
-}
-
 SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
     ResourceLimitCategory category) const {
     return impl->resource_limits.at(static_cast<std::size_t>(category));
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 41554821f1..7f822d5242 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -47,12 +47,6 @@ public:
     /// Clears all resources in use by the kernel instance.
     void Shutdown();
 
-    /// Provides a reference to the handle table.
-    Kernel::HandleTable& HandleTable();
-
-    /// Provides a const reference to the handle table.
-    const Kernel::HandleTable& HandleTable() const;
-
     /// Retrieves a shared pointer to a ResourceLimit identified by the given category.
     SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const;
 
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f2816943a2..1484784881 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -13,6 +13,7 @@
 #include <boost/container/static_vector.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
+#include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/vm_manager.h"
@@ -142,6 +143,16 @@ public:
         return vm_manager;
     }
 
+    /// Gets a reference to the process' handle table.
+    HandleTable& GetHandleTable() {
+        return handle_table;
+    }
+
+    /// Gets a const reference to the process' handle table.
+    const HandleTable& GetHandleTable() const {
+        return handle_table;
+    }
+
     /// Gets the current status of the process
     ProcessStatus GetStatus() const {
         return status;
@@ -294,6 +305,9 @@ private:
     /// specified by metadata provided to the process during loading.
     bool is_64bit_process = true;
 
+    /// Per-process handle table for storing created object handles in.
+    HandleTable handle_table;
+
     std::string name;
 };
 
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 1ece691c7e..5fc3204036 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -107,8 +107,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
     // similar.
     Kernel::HLERequestContext context(this);
     u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
-    context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(),
-                                              kernel.HandleTable());
+    context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
 
     ResultCode result = RESULT_SUCCESS;
     // If the session has been converted to a domain, handle the domain request
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 3b8a2e2301..4bd0b88c3b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -189,14 +189,15 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
     CASCADE_RESULT(client_session, client_port->Connect());
 
     // Return the client session
-    CASCADE_RESULT(*out_handle, kernel.HandleTable().Create(client_session));
+    auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
     return RESULT_SUCCESS;
 }
 
 /// Makes a blocking IPC call to an OS service.
 static ResultCode SendSyncRequest(Handle handle) {
-    auto& kernel = Core::System::GetInstance().Kernel();
-    SharedPtr<ClientSession> session = kernel.HandleTable().Get<ClientSession>(handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle);
     if (!session) {
         LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
         return ERR_INVALID_HANDLE;
@@ -215,8 +216,8 @@ static ResultCode SendSyncRequest(Handle handle) {
 static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
     LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
@@ -229,8 +230,8 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
 static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
     LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
     if (!process) {
         return ERR_INVALID_HANDLE;
     }
@@ -273,11 +274,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
 
     using ObjectPtr = Thread::ThreadWaitObjects::value_type;
     Thread::ThreadWaitObjects objects(handle_count);
-    auto& kernel = Core::System::GetInstance().Kernel();
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
 
     for (u64 i = 0; i < handle_count; ++i) {
         const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
-        const auto object = kernel.HandleTable().Get<WaitObject>(handle);
+        const auto object = handle_table.Get<WaitObject>(handle);
 
         if (object == nullptr) {
             return ERR_INVALID_HANDLE;
@@ -325,8 +326,8 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
 static ResultCode CancelSynchronization(Handle thread_handle) {
     LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
@@ -354,7 +355,7 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
         return ERR_INVALID_ADDRESS;
     }
 
-    auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
+    auto& handle_table = Core::CurrentProcess()->GetHandleTable();
     return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
                              requesting_thread_handle);
 }
@@ -499,13 +500,12 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
 static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
     LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
+    const auto* current_process = Core::CurrentProcess();
+    const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
 
-    const auto* current_process = Core::CurrentProcess();
     if (thread->GetOwnerProcess() != current_process) {
         return ERR_INVALID_HANDLE;
     }
@@ -531,10 +531,11 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
 
 /// Gets the priority for the specified thread
 static ResultCode GetThreadPriority(u32* priority, Handle handle) {
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
-    if (!thread)
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
+    if (!thread) {
         return ERR_INVALID_HANDLE;
+    }
 
     *priority = thread->GetPriority();
     return RESULT_SUCCESS;
@@ -546,14 +547,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
         return ERR_INVALID_THREAD_PRIORITY;
     }
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
-    if (!thread)
+    const auto* const current_process = Core::CurrentProcess();
+    SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+    if (!thread) {
         return ERR_INVALID_HANDLE;
+    }
 
     // Note: The kernel uses the current process's resource limit instead of
     // the one from the thread owner's resource limit.
-    const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
+    const ResourceLimit& resource_limit = current_process->GetResourceLimit();
     if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
         return ERR_NOT_AUTHORIZED;
     }
@@ -595,15 +597,13 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
         return ERR_INVALID_MEMORY_PERMISSIONS;
     }
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
+    auto* const current_process = Core::CurrentProcess();
+    auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
     if (!shared_memory) {
         return ERR_INVALID_HANDLE;
     }
 
-    auto* const current_process = Core::CurrentProcess();
     const auto& vm_manager = current_process->VMManager();
-
     if (!vm_manager.IsWithinASLRRegion(addr, size)) {
         return ERR_INVALID_MEMORY_RANGE;
     }
@@ -627,15 +627,13 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
         return ERR_INVALID_ADDRESS_STATE;
     }
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
+    auto* const current_process = Core::CurrentProcess();
+    auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
     if (!shared_memory) {
         return ERR_INVALID_HANDLE;
     }
 
-    auto* const current_process = Core::CurrentProcess();
     const auto& vm_manager = current_process->VMManager();
-
     if (!vm_manager.IsWithinASLRRegion(addr, size)) {
         return ERR_INVALID_MEMORY_RANGE;
     }
@@ -646,9 +644,8 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
 /// Query process memory
 static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
                                      Handle process_handle, u64 addr) {
-
-    auto& kernel = Core::System::GetInstance().Kernel();
-    SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
     if (!process) {
         return ERR_INVALID_HANDLE;
     }
@@ -695,20 +692,19 @@ static void ExitProcess() {
 /// Creates a new thread
 static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
                                u32 priority, s32 processor_id) {
-    std::string name = fmt::format("thread-{:X}", entry_point);
-
     if (priority > THREADPRIO_LOWEST) {
         return ERR_INVALID_THREAD_PRIORITY;
     }
 
-    const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
+    auto* const current_process = Core::CurrentProcess();
+    const ResourceLimit& resource_limit = current_process->GetResourceLimit();
     if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
         return ERR_NOT_AUTHORIZED;
     }
 
     if (processor_id == THREADPROCESSORID_DEFAULT) {
         // Set the target CPU to the one specified in the process' exheader.
-        processor_id = Core::CurrentProcess()->GetDefaultProcessorID();
+        processor_id = current_process->GetDefaultProcessorID();
         ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
     }
 
@@ -723,11 +719,13 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
         return ERR_INVALID_PROCESSOR_ID;
     }
 
+    const std::string name = fmt::format("thread-{:X}", entry_point);
     auto& kernel = Core::System::GetInstance().Kernel();
     CASCADE_RESULT(SharedPtr<Thread> thread,
                    Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
-                                  *Core::CurrentProcess()));
-    const auto new_guest_handle = kernel.HandleTable().Create(thread);
+                                  *current_process));
+
+    const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
     if (new_guest_handle.Failed()) {
         return new_guest_handle.Code();
     }
@@ -748,8 +746,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
 static ResultCode StartThread(Handle thread_handle) {
     LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
@@ -796,8 +794,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
         "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
         mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     ASSERT(thread);
 
     CASCADE_CODE(Mutex::Release(mutex_addr));
@@ -908,9 +906,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
                                                mutex_val | Mutex::MutexHasWaitersFlag));
 
             // The mutex is already owned by some other thread, make this thread wait on it.
-            auto& kernel = Core::System::GetInstance().Kernel();
-            Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
-            auto owner = kernel.HandleTable().Get<Thread>(owner_handle);
+            const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
+            const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+            auto owner = handle_table.Get<Thread>(owner_handle);
             ASSERT(owner);
             ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
             thread->InvalidateWakeupCallback();
@@ -989,16 +987,16 @@ static u64 GetSystemTick() {
 static ResultCode CloseHandle(Handle handle) {
     LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    return kernel.HandleTable().Close(handle);
+    auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    return handle_table.Close(handle);
 }
 
 /// Reset an event
 static ResultCode ResetSignal(Handle handle) {
     LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    auto event = kernel.HandleTable().Get<Event>(handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    auto event = handle_table.Get<Event>(handle);
 
     ASSERT(event != nullptr);
 
@@ -1017,8 +1015,8 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
 static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
     LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
@@ -1033,8 +1031,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
     LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
               mask, core);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
     if (!thread) {
         return ERR_INVALID_HANDLE;
     }
@@ -1095,7 +1093,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
     }
 
     auto& kernel = Core::System::GetInstance().Kernel();
-    auto& handle_table = kernel.HandleTable();
+    auto& handle_table = Core::CurrentProcess()->GetHandleTable();
     auto shared_mem_handle =
         SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
                              local_perms, remote_perms);
@@ -1107,10 +1105,12 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
 static ResultCode ClearEvent(Handle handle) {
     LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
 
-    auto& kernel = Core::System::GetInstance().Kernel();
-    SharedPtr<Event> evt = kernel.HandleTable().Get<Event>(handle);
-    if (evt == nullptr)
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    SharedPtr<Event> evt = handle_table.Get<Event>(handle);
+    if (evt == nullptr) {
         return ERR_INVALID_HANDLE;
+    }
+
     evt->Clear();
     return RESULT_SUCCESS;
 }
@@ -1123,8 +1123,8 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
         Status,
     };
 
-    const auto& kernel = Core::System::GetInstance().Kernel();
-    const auto process = kernel.HandleTable().Get<Process>(process_handle);
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
+    const auto process = handle_table.Get<Process>(process_handle);
     if (!process) {
         return ERR_INVALID_HANDLE;
     }
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 35ec98c1a5..59bc9e0af6 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -266,7 +266,7 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
     SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
 
     // Register 1 must be a handle to the main thread
-    const Handle guest_handle = kernel.HandleTable().Create(thread).Unwrap();
+    const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
     thread->SetGuestHandle(guest_handle);
     thread->GetContext().cpu_registers[1] = guest_handle;
 
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 7403e9ccd8..0c831c9f47 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -9,8 +9,8 @@
 #include "core/core.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/mutex.h"
+#include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/timer.h"
@@ -83,7 +83,7 @@ QString WaitTreeText::GetText() const {
 }
 
 WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) {
-    auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
+    const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
 
     mutex_value = Memory::Read32(mutex_address);
     owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);