diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp
index e859cc538..d40fa66ae 100644
--- a/src/input_common/drivers/android.cpp
+++ b/src/input_common/drivers/android.cpp
@@ -3,6 +3,7 @@
 
 #include <set>
 #include <common/settings_input.h>
+#include <common/thread.h>
 #include <jni.h>
 #include "common/android/android_common.h"
 #include "common/android/id_cache.h"
@@ -10,7 +11,18 @@
 
 namespace InputCommon {
 
-Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
+Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
+    vibration_thread = std::jthread([this](std::stop_token token) {
+        Common::SetCurrentThreadName("Android_Vibration");
+        auto env = Common::Android::GetEnvForThread();
+        using namespace std::chrono_literals;
+        while (!token.stop_requested()) {
+            SendVibrations(env, token);
+        }
+    });
+}
+
+Android::~Android() = default;
 
 void Android::RegisterController(jobject j_input_device) {
     auto env = Common::Android::GetEnvForThread();
@@ -57,17 +69,11 @@ void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp,
 Common::Input::DriverResult Android::SetVibration(
     [[maybe_unused]] const PadIdentifier& identifier,
     [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
-    auto device = input_devices.find(identifier);
-    if (device != input_devices.end()) {
-        Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) {
-            float average_intensity =
-                static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0);
-            env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
-                                average_intensity);
-        });
-        return Common::Input::DriverResult::Success;
-    }
-    return Common::Input::DriverResult::NotSupported;
+    vibration_queue.Push(VibrationRequest{
+        .identifier = identifier,
+        .vibration = vibration,
+    });
+    return Common::Input::DriverResult::Success;
 }
 
 bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
@@ -347,4 +353,15 @@ PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const
     };
 }
 
+void Android::SendVibrations(JNIEnv* env, std::stop_token token) {
+    VibrationRequest request = vibration_queue.PopWait(token);
+    auto device = input_devices.find(request.identifier);
+    if (device != input_devices.end()) {
+        float average_intensity = static_cast<float>(
+            (request.vibration.high_amplitude + request.vibration.low_amplitude) / 2.0);
+        env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
+                            average_intensity);
+    }
+}
+
 } // namespace InputCommon
diff --git a/src/input_common/drivers/android.h b/src/input_common/drivers/android.h
index 8a386c1b1..03e2b2c98 100644
--- a/src/input_common/drivers/android.h
+++ b/src/input_common/drivers/android.h
@@ -4,6 +4,7 @@
 #pragma once
 
 #include <set>
+#include <common/threadsafe_queue.h>
 #include <jni.h>
 #include "input_common/input_engine.h"
 
@@ -16,6 +17,8 @@ class Android final : public InputEngine {
 public:
     explicit Android(std::string input_engine_);
 
+    ~Android() override;
+
     /**
      * Registers controller number to accept new inputs.
      * @param j_input_device YuzuInputDevice object from the Android frontend to register.
@@ -89,6 +92,9 @@ private:
     /// Returns the correct identifier corresponding to the player index
     PadIdentifier GetIdentifier(const std::string& guid, size_t port) const;
 
+    /// Takes all vibrations from the queue and sends the command to the controller
+    void SendVibrations(JNIEnv* env, std::stop_token token);
+
     static constexpr s32 AXIS_X = 0;
     static constexpr s32 AXIS_Y = 1;
     static constexpr s32 AXIS_Z = 11;
@@ -133,6 +139,10 @@ private:
                                                    redmagic_vid, backbone_labs_vid, xbox_vid};
     const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid,
                                                    backbone_labs_vid, xbox_vid};
+
+    /// Queue of vibration request to controllers
+    Common::SPSCQueue<VibrationRequest> vibration_queue;
+    std::jthread vibration_thread;
 };
 
 } // namespace InputCommon
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index 08e49a0da..a140ad072 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -69,11 +69,6 @@ public:
     bool IsVibrationEnabled(const PadIdentifier& identifier) override;
 
 private:
-    struct VibrationRequest {
-        PadIdentifier identifier;
-        Common::Input::VibrationStatus vibration;
-    };
-
     void InitJoystick(int joystick_index);
     void CloseJoystick(SDL_Joystick* sdl_joystick);
 
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index c2d0cbb34..3e328509b 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -46,6 +46,11 @@ enum class EngineInputType {
     Nfc,
 };
 
+struct VibrationRequest {
+    PadIdentifier identifier;
+    Common::Input::VibrationStatus vibration;
+};
+
 namespace std {
 // Hash used to create lists from PadIdentifier data
 template <>