diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index 51b8d91aba..290462fa8b 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -66,6 +66,8 @@ namespace Ryujinx.Graphics.GAL
 
         void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer);
 
+        void SetUserClipDistance(int index, bool enableClip);
+
         void SetVertexAttribs(VertexAttribDescriptor[] vertexAttribs);
         void SetVertexBuffers(VertexBufferDescriptor[] vertexBuffers);
 
diff --git a/Ryujinx.Graphics.Gpu/Constants.cs b/Ryujinx.Graphics.Gpu/Constants.cs
index 3175ebd2fa..1ae902731c 100644
--- a/Ryujinx.Graphics.Gpu/Constants.cs
+++ b/Ryujinx.Graphics.Gpu/Constants.cs
@@ -54,5 +54,10 @@ namespace Ryujinx.Graphics.Gpu
         /// Maximum number of viewports.
         /// </summary>
         public const int TotalViewports = 16;
+
+        /// <summary>
+        /// Maximum size of gl_ClipDistance array in shaders.
+        /// </summary>
+        public const int TotalClipDistances = 8;
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index a517ae05dd..59678be59f 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -125,6 +125,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 UpdateShaderState(state);
             }
 
+            if (state.QueryModified(MethodOffset.ClipDistanceEnable))
+            {
+                UpdateUserClipState(state);
+            }
+
             if (state.QueryModified(MethodOffset.RasterizeEnable))
             {
                 UpdateRasterizerState(state);
@@ -902,6 +907,20 @@ namespace Ryujinx.Graphics.Gpu.Engine
             _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
         }
 
+        /// <summary>
+        /// Updates user-defined clipping based on the guest GPU state.
+        /// </summary>
+        /// <param name="state">Current GPU state</param>
+        private void UpdateUserClipState(GpuState state)
+        {
+            int clipMask = state.Get<int>(MethodOffset.ClipDistanceEnable);
+
+            for (int i = 0; i < Constants.TotalClipDistances; ++i)
+            {
+                _context.Renderer.Pipeline.SetUserClipDistance(i, (clipMask & (1 << i)) != 0);
+            }
+        }
+
         /// <summary>
         /// Gets texture target from a sampler type.
         /// </summary>
diff --git a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
index 077b09c271..b39ff9b5e0 100644
--- a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
+++ b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
@@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.Gpu.State
         YControl                        = 0x4eb,
         FirstVertex                     = 0x50d,
         FirstInstance                   = 0x50e,
+        ClipDistanceEnable              = 0x544,
         PointSize                       = 0x546,
         ResetCounter                    = 0x54c,
         RtDepthStencilEnable            = 0x54e,
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 604d0ba30a..dc04805dac 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -811,6 +811,17 @@ namespace Ryujinx.Graphics.OpenGL
             SetBuffer(index, stage, buffer, isStorage: false);
         }
 
+        public void SetUserClipDistance(int index, bool enableClip)
+        {
+            if (!enableClip)
+            {
+                GL.Disable(EnableCap.ClipDistance0 + index);
+                return;
+            }
+
+            GL.Enable(EnableCap.ClipDistance0 + index);
+        }
+
         public void SetVertexAttribs(VertexAttribDescriptor[] vertexAttribs)
         {
             EnsureVertexArray();