diff --git a/Data/Conduit.hs b/Data/Conduit.hs
--- a/Data/Conduit.hs
+++ b/Data/Conduit.hs
@@ -16,6 +16,10 @@
     , (=$)
     , (=$=)
 
+      -- *** Fuse with upstream results
+    , fuseBoth
+    , fuseUpstream
+
       -- ** Primitives
     , await
     , yield
@@ -489,3 +493,21 @@
 -- Since 1.0.17
 sequenceConduits :: (Traversable f, Monad m) => f (ConduitM i o m r) -> ConduitM i o m (f r)
 sequenceConduits = getZipConduit . sequenceA . fmap ZipConduit
+
+-- | Fuse two @ConduitM@s together, and provide the return value of both. Note
+-- that this will force the entire upstream @ConduitM@ to be run to produce the
+-- result value, even if the downstream terminates early.
+--
+-- Since 1.1.5
+fuseBoth :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (r1, r2)
+fuseBoth (ConduitM up) (ConduitM down) =
+    ConduitM $ pipeL up (withUpstream $ generalizeUpstream down)
+{-# INLINE fuseBoth #-}
+
+-- | Same as @fuseBoth@, but ignore the return value from the downstream
+-- @Conduit@. Same caveats of forced consumption apply.
+--
+-- Since 1.1.5
+fuseUpstream :: Monad m => ConduitM a b m r -> Conduit b m c -> ConduitM a c m r
+fuseUpstream up down = fmap fst (fuseBoth up down)
+{-# INLINE fuseUpstream #-}
diff --git a/Data/Conduit/Internal.hs b/Data/Conduit/Internal.hs
--- a/Data/Conduit/Internal.hs
+++ b/Data/Conduit/Internal.hs
@@ -72,6 +72,7 @@
     , zipSourcesApp
     , zipConduitApp
     , passthroughSink
+    , generalizeUpstream
     ) where
 
 import Control.Applicative (Applicative (..))
@@ -1112,3 +1113,17 @@
             Just x -> do
                 yield x
                 go [] (next x)
+
+-- | Generalize the upstream return value for a @Pipe@ from unit to any type.
+--
+-- Since 1.1.5
+generalizeUpstream :: Monad m => Pipe l i o () m r -> Pipe l i o u m r
+generalizeUpstream =
+    go
+  where
+    go (HaveOutput p f o) = HaveOutput (go p) f o
+    go (NeedInput x y) = NeedInput (go . x) (\_ -> go (y ()))
+    go (Done r) = Done r
+    go (PipeM mp) = PipeM (liftM go mp)
+    go (Leftover p l) = Leftover (go p) l
+{-# INLINE generalizeUpstream #-}
diff --git a/conduit.cabal b/conduit.cabal
--- a/conduit.cabal
+++ b/conduit.cabal
@@ -1,5 +1,5 @@
 Name:                conduit
-Version:             1.1.4
+Version:             1.1.5
 Synopsis:            Streaming data processing library.
 Description:
     @conduit@ is a solution to the streaming data problem, allowing for production, transformation, and consumption of streams of data in constant memory. It is an alternative to lazy I\/O which guarantees deterministic resource handling, and fits in the same general solution space as @enumerator@\/@iteratee@ and @pipes@. For a tutorial, please visit <https://haskell.fpcomplete.com/user/snoyberg/library-documentation/conduit-overview>.
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -887,6 +887,18 @@
             x <- C.runResourceT $ CL.sourceList [100,99..1] C.$$ sink
             x `shouldBe` (505000 :: Integer)
 
+    describe "upstream results" $ do
+        it "fuseBoth" $ do
+            let upstream = do
+                    C.yield ("hello" :: String)
+                    CL.isolate 5 C.=$= CL.fold (+) 0
+                downstream = C.fuseBoth upstream CL.consume
+            res <- CL.sourceList [1..10 :: Int] C.$$ do
+                (x, y) <- downstream
+                z <- CL.consume
+                return (x, y, z)
+            res `shouldBe` (sum [1..5], ["hello"], [6..10])
+
     ZipConduit.spec
 
 it' :: String -> IO () -> Spec
