diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c59f3af1b..7e1bba67d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include <array>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -58,6 +59,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
 
         if (extension == "GL_ARB_direct_state_access") {
             has_ARB_direct_state_access = true;
+        } else if (extension == "GL_ARB_multi_bind") {
+            has_ARB_multi_bind = true;
         } else if (extension == "GL_ARB_separate_shader_objects") {
             has_ARB_separate_shader_objects = true;
         } else if (extension == "GL_ARB_vertex_attrib_binding") {
@@ -644,12 +647,23 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
     const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
     const auto& entries = shader->GetShaderEntries().const_buffer_entries;
 
+    constexpr u64 max_binds = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers;
+    std::array<GLuint, max_binds> bind_buffers;
+    std::array<GLintptr, max_binds> bind_offsets;
+    std::array<GLsizeiptr, max_binds> bind_sizes;
+
+    ASSERT_MSG(entries.size() <= max_binds, "Exceeded expected number of binding points.");
+
     // Upload only the enabled buffers from the 16 constbuffers of each shader stage
     for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
         const auto& used_buffer = entries[bindpoint];
         const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
 
         if (!buffer.enabled) {
+            // With disabled buffers set values as zero to unbind them
+            bind_buffers[bindpoint] = 0;
+            bind_offsets[bindpoint] = 0;
+            bind_sizes[bindpoint] = 0;
             continue;
         }
 
@@ -677,15 +691,20 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
         GLintptr const_buffer_offset = buffer_cache.UploadMemory(
             buffer.address, size, static_cast<size_t>(uniform_buffer_alignment));
 
-        glBindBufferRange(GL_UNIFORM_BUFFER, current_bindpoint + bindpoint,
-                          buffer_cache.GetHandle(), const_buffer_offset, size);
-
         // Now configure the bindpoint of the buffer inside the shader
         glUniformBlockBinding(shader->GetProgramHandle(),
                               shader->GetProgramResourceIndex(used_buffer),
                               current_bindpoint + bindpoint);
+
+        // Prepare values for multibind
+        bind_buffers[bindpoint] = buffer_cache.GetHandle();
+        bind_offsets[bindpoint] = const_buffer_offset;
+        bind_sizes[bindpoint] = size;
     }
 
+    glBindBuffersRange(GL_UNIFORM_BUFFER, current_bindpoint, static_cast<GLsizei>(entries.size()),
+                       bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
+
     return current_bindpoint + static_cast<u32>(entries.size());
 }
 
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 745c3dc0c..163412882 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -159,6 +159,7 @@ private:
     void SyncLogicOpState();
 
     bool has_ARB_direct_state_access = false;
+    bool has_ARB_multi_bind = false;
     bool has_ARB_separate_shader_objects = false;
     bool has_ARB_vertex_attrib_binding = false;
 
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 05a4a55e8..22a317737 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -449,6 +449,8 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() {
         unsupported_ext.append("ARB_base_instance");
     if (!GLAD_GL_ARB_texture_storage)
         unsupported_ext.append("ARB_texture_storage");
+    if (!GLAD_GL_ARB_multi_bind)
+        unsupported_ext.append("ARB_multi_bind");
 
     // Extensions required to support some texture formats.
     if (!GLAD_GL_EXT_texture_compression_s3tc)
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index d213929bd..0733301b2 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -96,6 +96,8 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
         unsupported_ext.push_back("ARB_base_instance");
     if (!GLAD_GL_ARB_texture_storage)
         unsupported_ext.push_back("ARB_texture_storage");
+    if (!GLAD_GL_ARB_multi_bind)
+        unsupported_ext.push_back("ARB_multi_bind");
 
     // Extensions required to support some texture formats.
     if (!GLAD_GL_EXT_texture_compression_s3tc)