diff --git a/splint.cabal b/splint.cabal
--- a/splint.cabal
+++ b/splint.cabal
@@ -1,7 +1,7 @@
 cabal-version: >= 1.10
 
 name: splint
-version: 1.0.1.3
+version: 1.0.1.4
 
 synopsis: HLint as a GHC source plugin.
 description:
@@ -26,7 +26,7 @@
     base >= 4.13.0 && < 4.16
     , containers >= 0.6.2 && < 0.7
     , ghc >= 8.8.4 && < 8.11 || >= 9.0.1 && < 9.1
-    , hlint >= 3.1.6 && < 3.3
+    , hlint >= 3.1.6 && < 3.4
     , stm >= 2.5.0 && < 2.6
   default-language: Haskell2010
   exposed-modules: Splint
@@ -34,15 +34,24 @@
     -Weverything
     -Wno-implicit-prelude
     -Wno-missing-deriving-strategies
+    -Wno-missing-export-lists
     -Wno-missing-exported-signatures
+    -Wno-missing-import-lists
     -Wno-unsafe
   hs-source-dirs: src/lib
-  other-modules: Splint.Parser
+  other-modules:
+    Splint.GHC.Bag
+    Splint.GHC.Error
+    Splint.GHC.Plugins
+    Splint.Parser
 
-  if impl(ghc >= 8.10)
-    other-modules: Splint.Parser.Native
+  if impl(ghc >= 9.0)
+    hs-source-dirs: src/ghc-9.0
   else
-    other-modules: Splint.Parser.Fallback
+    if impl(ghc >= 8.10)
+      hs-source-dirs: src/ghc-8.10
+    else
+      hs-source-dirs: src/ghc-8.8
 
   if impl(ghc >= 8.10)
     ghc-options:
diff --git a/src/ghc-8.10/Splint/GHC/Bag.hs b/src/ghc-8.10/Splint/GHC/Bag.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.10/Splint/GHC/Bag.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Bag ( module Export ) where
+
+import Bag as Export
diff --git a/src/ghc-8.10/Splint/GHC/Error.hs b/src/ghc-8.10/Splint/GHC/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.10/Splint/GHC/Error.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Error ( module Export ) where
+
+import ErrUtils as Export
diff --git a/src/ghc-8.10/Splint/GHC/Plugins.hs b/src/ghc-8.10/Splint/GHC/Plugins.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.10/Splint/GHC/Plugins.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Plugins ( module Export ) where
+
+import GhcPlugins as Export
diff --git a/src/ghc-8.10/Splint/Parser.hs b/src/ghc-8.10/Splint/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.10/Splint/Parser.hs
@@ -0,0 +1,15 @@
+module Splint.Parser where
+
+import qualified Language.Haskell.HLint as HLint
+import qualified Splint.GHC.Plugins as GHC
+
+parse
+  :: HLint.ParseFlags
+  -> GHC.ModSummary
+  -> GHC.HsParsedModule
+  -> GHC.Hsc HLint.ModuleEx
+parse _ _ hsParsedModule = do
+  let
+    apiAnns = GHC.hpm_annotations hsParsedModule
+    hsModule = GHC.hpm_module hsParsedModule
+  pure $ HLint.createModuleEx apiAnns hsModule
diff --git a/src/ghc-8.8/Splint/GHC/Bag.hs b/src/ghc-8.8/Splint/GHC/Bag.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.8/Splint/GHC/Bag.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Bag ( module Export ) where
+
+import Bag as Export
diff --git a/src/ghc-8.8/Splint/GHC/Error.hs b/src/ghc-8.8/Splint/GHC/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.8/Splint/GHC/Error.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Error ( module Export ) where
+
+import ErrUtils as Export
diff --git a/src/ghc-8.8/Splint/GHC/Plugins.hs b/src/ghc-8.8/Splint/GHC/Plugins.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.8/Splint/GHC/Plugins.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Plugins ( module Export ) where
+
+import GhcPlugins as Export
diff --git a/src/ghc-8.8/Splint/Parser.hs b/src/ghc-8.8/Splint/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-8.8/Splint/Parser.hs
@@ -0,0 +1,32 @@
+module Splint.Parser where
+
+import qualified Control.Exception as Exception
+import qualified Language.Haskell.HLint as HLint
+import qualified Splint.GHC.Plugins as GHC
+
+parse
+  :: HLint.ParseFlags
+  -> GHC.ModSummary
+  -> GHC.HsParsedModule
+  -> GHC.Hsc HLint.ModuleEx
+parse parseFlags modSummary _ = GHC.liftIO $ do
+  let filePath = GHC.msHsFilePath modSummary
+  result <- HLint.parseModuleEx parseFlags filePath Nothing
+  case result of
+    Left parseError -> Exception.throwIO $ ParseError parseError
+    Right moduleEx -> pure moduleEx
+
+newtype ParseError = ParseError HLint.ParseError
+
+instance Exception.Exception ParseError
+
+instance Show ParseError where
+  show (ParseError parseError) = mconcat
+    [ "ParseError { parseErrorLocation = "
+    , show $ HLint.parseErrorLocation parseError
+    , ", parseErrorMessage = "
+    , show $ HLint.parseErrorMessage parseError
+    , ", parseErrorContents = "
+    , show $ HLint.parseErrorContents parseError
+    , " }"
+    ]
diff --git a/src/ghc-9.0/Splint/GHC/Bag.hs b/src/ghc-9.0/Splint/GHC/Bag.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-9.0/Splint/GHC/Bag.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Bag ( module Export ) where
+
+import GHC.Data.Bag as Export
diff --git a/src/ghc-9.0/Splint/GHC/Error.hs b/src/ghc-9.0/Splint/GHC/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-9.0/Splint/GHC/Error.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Error ( module Export ) where
+
+import GHC.Utils.Error as Export
diff --git a/src/ghc-9.0/Splint/GHC/Plugins.hs b/src/ghc-9.0/Splint/GHC/Plugins.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-9.0/Splint/GHC/Plugins.hs
@@ -0,0 +1,3 @@
+module Splint.GHC.Plugins ( module Export ) where
+
+import GHC.Plugins as Export
diff --git a/src/ghc-9.0/Splint/Parser.hs b/src/ghc-9.0/Splint/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/ghc-9.0/Splint/Parser.hs
@@ -0,0 +1,15 @@
+module Splint.Parser where
+
+import qualified Language.Haskell.HLint as HLint
+import qualified Splint.GHC.Plugins as GHC
+
+parse
+  :: HLint.ParseFlags
+  -> GHC.ModSummary
+  -> GHC.HsParsedModule
+  -> GHC.Hsc HLint.ModuleEx
+parse _ _ hsParsedModule = do
+  let
+    apiAnns = GHC.hpm_annotations hsParsedModule
+    hsModule = GHC.hpm_module hsParsedModule
+  pure $ HLint.createModuleEx apiAnns hsModule
diff --git a/src/lib/Splint.hs b/src/lib/Splint.hs
--- a/src/lib/Splint.hs
+++ b/src/lib/Splint.hs
@@ -3,14 +3,14 @@
   )
 where
 
-import qualified Bag as GHC
+import qualified Splint.GHC.Bag as GHC
 import qualified Control.Concurrent as Concurrent
 import qualified Control.Concurrent.STM as Stm
 import qualified Control.Exception as Exception
 import qualified Control.Monad.IO.Class as IO
 import qualified Data.Map as Map
-import qualified ErrUtils as GHC
-import qualified GhcPlugins as GHC
+import qualified Splint.GHC.Error as GHC
+import qualified Splint.GHC.Plugins as GHC
 import qualified Language.Haskell.HLint as HLint
 import qualified Splint.Parser as Splint
 import qualified System.IO.Unsafe as Unsafe
diff --git a/src/lib/Splint/Parser.hs b/src/lib/Splint/Parser.hs
deleted file mode 100644
--- a/src/lib/Splint/Parser.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-{-# LANGUAGE CPP #-}
-
--- | Starting with HLint 3, it's possible to re-use the parsed module that GHC
--- produces to avoid re-parsing the module. Unfortunately this is only possible
--- when the GHC version matches the version that HLint expects. Otherwise we
--- have to let HLint re-parse the module to produce it's expected AST.
---
--- This module is responsible for picking that behavior. The so-called "native"
--- behavior is the one where GHC's parse module is re-used. The "fallback"
--- parser is the one that re-parses the module.
---
--- Doing this requires a build-time decision, which means using CPP. Therefore
--- this module is kept as small as possible in order to make it easier to
--- reason about.
---
--- It is expected that both the "native" and "fallback" parsers expose the
--- exact same interface.
---
--- You could in theory always use the "fallback" parser, but that would mean
--- doing a lot of unnecessary work by re-parsing modules. Parsing is typically
--- fast and this is hard to quantify, so if you want to go that route you
--- should consider using Ollie Charles's hlint-source-plugin instead.
--- <https://github.com/ocharles/hlint-source-plugin>
-module Splint.Parser
-  ( parse
-  )
-where
-
-#if (__GLASGOW_HASKELL__ == 810)
-import Splint.Parser.Native (parse)
-#else
-import Splint.Parser.Fallback (parse)
-#endif
diff --git a/src/lib/Splint/Parser/Fallback.hs b/src/lib/Splint/Parser/Fallback.hs
deleted file mode 100644
--- a/src/lib/Splint/Parser/Fallback.hs
+++ /dev/null
@@ -1,35 +0,0 @@
-module Splint.Parser.Fallback
-  ( parse
-  )
-where
-
-import qualified Control.Exception as Exception
-import qualified GhcPlugins as GHC
-import qualified Language.Haskell.HLint as HLint
-
-parse
-  :: HLint.ParseFlags
-  -> GHC.ModSummary
-  -> GHC.HsParsedModule
-  -> GHC.Hsc HLint.ModuleEx
-parse parseFlags modSummary _ = GHC.liftIO $ do
-  let filePath = GHC.msHsFilePath modSummary
-  result <- HLint.parseModuleEx parseFlags filePath Nothing
-  case result of
-    Left parseError -> Exception.throwIO $ ParseError parseError
-    Right moduleEx -> pure moduleEx
-
-newtype ParseError = ParseError HLint.ParseError
-
-instance Exception.Exception ParseError
-
-instance Show ParseError where
-  show (ParseError parseError) = mconcat
-    [ "ParseError { parseErrorLocation = "
-    , show $ HLint.parseErrorLocation parseError
-    , ", parseErrorMessage = "
-    , show $ HLint.parseErrorMessage parseError
-    , ", parseErrorContents = "
-    , show $ HLint.parseErrorContents parseError
-    , " }"
-    ]
diff --git a/src/lib/Splint/Parser/Native.hs b/src/lib/Splint/Parser/Native.hs
deleted file mode 100644
--- a/src/lib/Splint/Parser/Native.hs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Splint.Parser.Native
-  ( parse
-  )
-where
-
-import qualified GhcPlugins as GHC
-import qualified Language.Haskell.HLint as HLint
-
-parse
-  :: HLint.ParseFlags
-  -> GHC.ModSummary
-  -> GHC.HsParsedModule
-  -> GHC.Hsc HLint.ModuleEx
-parse _ _ hsParsedModule = do
-  let
-    apiAnns = GHC.hpm_annotations hsParsedModule
-    hsModule = GHC.hpm_module hsParsedModule
-  pure $ HLint.createModuleEx apiAnns hsModule
