diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 21207fe99b..7c7c2459c9 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -763,19 +763,6 @@ void KThread::Continue() {
     KScheduler::OnThreadStateChanged(kernel, this, old_state);
 }
 
-void KThread::WaitUntilSuspended() {
-    // Make sure we have a suspend requested.
-    ASSERT(IsSuspendRequested());
-
-    // Loop until the thread is not executing on any core.
-    for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
-        KThread* core_thread{};
-        do {
-            core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread();
-        } while (core_thread == this);
-    }
-}
-
 Result KThread::SetActivity(Svc::ThreadActivity activity) {
     // Lock ourselves.
     KScopedLightLock lk(activity_pause_lock);
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 7cd94a340e..083f4962d6 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -214,8 +214,6 @@ public:
 
     void Continue();
 
-    void WaitUntilSuspended();
-
     constexpr void SetSyncedIndex(s32 index) {
         synced_index = index;
     }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1fb25f2219..d9eafe2613 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1198,27 +1198,34 @@ void KernelCore::Suspend(bool suspended) {
     const bool should_suspend{exception_exited || suspended};
     const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
 
-    std::vector<KScopedAutoObject<KThread>> process_threads;
-    {
-        KScopedSchedulerLock sl{*this};
-
-        if (auto* process = CurrentProcess(); process != nullptr) {
-            process->SetActivity(activity);
-
-            if (!should_suspend) {
-                // Runnable now; no need to wait.
-                return;
-            }
-
-            for (auto* thread : process->GetThreadList()) {
-                process_threads.emplace_back(thread);
-            }
-        }
+    //! This refers to the application process, not the current process.
+    KScopedAutoObject<KProcess> process = CurrentProcess();
+    if (process.IsNull()) {
+        return;
     }
 
-    // Wait for execution to stop.
-    for (auto& thread : process_threads) {
-        thread->WaitUntilSuspended();
+    // Set the new activity.
+    process->SetActivity(activity);
+
+    // Wait for process execution to stop.
+    bool must_wait{should_suspend};
+
+    // KernelCore::Suspend must be called from locked context, or we
+    // could race another call to SetActivity, interfering with waiting.
+    while (must_wait) {
+        KScopedSchedulerLock sl{*this};
+
+        // Assume that all threads have finished running.
+        must_wait = false;
+
+        for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
+            if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() ==
+                process.GetPointerUnsafe()) {
+                // A thread has not finished running yet.
+                // Continue waiting.
+                must_wait = true;
+            }
+        }
     }
 }