diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -136,8 +136,8 @@
                           , (":authority", ByteString.pack _host)
                           ] <> _extraHeaders
 
-    let ppHandler _ stream streamFlowControl _ = void $ forkIO $ do
-            timePrint ("push stream started" :: String)
+    let ppHandler _ stream ppHdrs streamFlowControl _ = void $ forkIO $ do
+            timePrint ("push stream started" :: String, ppHdrs)
             waitStream stream streamFlowControl >>= timePrint . fromStreamResult
             timePrint ("push stream ended" :: String)
 
diff --git a/http2-client.cabal b/http2-client.cabal
--- a/http2-client.cabal
+++ b/http2-client.cabal
@@ -1,5 +1,5 @@
 name:                http2-client
-version:             0.2.0.2
+version:             0.3.0.0
 synopsis:            A native HTTP2 client library.
 description:         Please read the README.md at the homepage.
 homepage:            https://github.com/lucasdicioccio/http2-client
diff --git a/src/Network/HTTP2/Client.hs b/src/Network/HTTP2/Client.hs
--- a/src/Network/HTTP2/Client.hs
+++ b/src/Network/HTTP2/Client.hs
@@ -227,7 +227,7 @@
 -- client-initiated stream. Longer term we may move passing this handler to the
 -- '_startStream' instead of 'newHttp2Client' (as it is for now).
 type PushPromiseHandler =
-    StreamId -> Http2Stream -> IncomingFlowControl -> OutgoingFlowControl -> IO ()
+    StreamId -> Http2Stream -> HeaderList -> IncomingFlowControl -> OutgoingFlowControl -> IO ()
 
 -- | Helper to carry around the HPACK encoder for outgoing header blocks..
 data HpackEncoderContext = HpackEncoderContext {
@@ -411,9 +411,9 @@
   :: Exception e
   => Http2FrameConnection
   -> IORef ConnectionSettings
-  -> Chan (FrameHeader, Either e FramePayload)
-  -> Chan (FrameHeader, StreamId, Either ErrorCode HeaderList)
-  -> Chan (StreamId, Chan (FrameHeader, Either e FramePayload), StreamId)
+  -> FramesChan e
+  -> HeadersChan
+  -> PushPromisesChan e
   -> HpackEncoderContext
   -> StreamId
   -> (Http2Stream -> StreamDefinition a)
@@ -450,12 +450,12 @@
     let _rst            = sendResetFrame frameStream
     let _prio           = sendPriorityFrame frameStream
     let _waitPushPromise ppHandler = do
-            (_,ppFrames,ppSid) <- waitPushPromiseWithParentStreamId sid pushPromises
-            let mkStreamActions stream = StreamDefinition (return CST) (ppHandler sid stream)
+            (_,ppFrames,ppHeaders,ppSid,ppReadHeaders) <- waitPushPromiseWithParentStreamId sid pushPromises
+            let mkStreamActions stream = StreamDefinition (return CST) (ppHandler sid stream ppReadHeaders)
             ppCont <- initializeStream conn
                                        settings
                                        ppFrames
-                                       serverHeaders
+                                       ppHeaders
                                        serverPushPromises
                                        hpackEncoder
                                        ppSid
@@ -534,11 +534,20 @@
     _ <- _consumeCredit flowControl (HTTP2.payloadLength fh)
     _addCredit flowControl (HTTP2.payloadLength fh)
 
+data HPACKLoopDecision =
+    ForwardHeader !StreamId
+  | OpenPushPromise !StreamId !StreamId
+
+type FramesChan e = Chan (FrameHeader, Either e FramePayload)
+type HeadersChan = Chan (FrameHeader, StreamId, Either ErrorCode HeaderList)
+type PushPromisesChanContent e = (StreamId, FramesChan e, HeadersChan, StreamId, HeaderList)
+type PushPromisesChan e = Chan (PushPromisesChanContent e)
+
 incomingHPACKFramesLoop
   :: Exception e
-  => Chan (FrameHeader, Either e FramePayload)
-  -> Chan (FrameHeader, StreamId, Either ErrorCode HeaderList)
-  -> Chan (StreamId, Chan (FrameHeader, Either e FramePayload), StreamId)
+  => FramesChan e
+  -> HeadersChan
+  -> PushPromisesChan e
   -> DynamicTable
   -> IO ()
 incomingHPACKFramesLoop frames hdrs pushPromises hpackDecoder = forever $ do
@@ -547,18 +556,14 @@
                                     , FrameHeaders
                                     ]
                                     frames
-    (sId, pattern) <- case fp of
-            PushPromiseFrame sid hbf -> do
-                -- Important: We duplicate the channel here or we risk losing
-                -- DATA frames sent over the stream.
-                ppChan <- dupChan frames
-                let parentSid = HTTP2.streamId fh
-                writeChan pushPromises (parentSid, ppChan, sid)
-                return (sid, Right hbf)
+    let sid = HTTP2.streamId fh
+    (decision, pattern) <- case fp of
+            PushPromiseFrame ppSid hbf -> do
+                return (OpenPushPromise sid ppSid, Right hbf)
             HeadersFrame _ hbf       -> -- TODO: handle priority
-                return (HTTP2.streamId fh, Right hbf)
+                return (ForwardHeader sid, Right hbf)
             RSTStreamFrame err       ->
-                return (HTTP2.streamId fh, Left err)
+                return (ForwardHeader sid, Left err)
             _                        -> error "wrong TypeId"
 
     let go curFh (Right buffer) =
@@ -576,10 +581,23 @@
                     _                     -> error "waitFrameWithTypeIdForStreamId returned an unknown frame"
             else do
                 newHdrs <- decodeHeader hpackDecoder buffer
-                writeChan hdrs (curFh, sId, Right newHdrs)
+                case decision of
+                    ForwardHeader sId ->
+                        writeChan hdrs (curFh, sId, Right newHdrs)
+                    OpenPushPromise parentSid newSid -> do
+                        -- Important: We duplicate the channel here or we risk
+                        -- losing DATA or HEADERS+CONTINUATION frames sent over
+                        -- the main stream because even though
+                        -- 'initializeStream' dupes frame channels, this
+                        -- function will has no guarantee that the parent
+                        -- stream and the push-promise handler that will
+                        -- initiate the new stream are synchronous.
+                        ppChan <- dupChan frames
+                        ppHeaders <- dupChan hdrs
+                        writeChan pushPromises (parentSid, ppChan, ppHeaders, newSid, newHdrs)
 
         go curFh (Left err) =
-                writeChan hdrs (curFh, sId, (Left $ HTTP2.fromErrorCodeId err))
+                writeChan hdrs (curFh, sid, (Left $ HTTP2.fromErrorCodeId err))
 
     go fh pattern
 
@@ -835,13 +853,13 @@
 
 waitPushPromiseWithParentStreamId
   :: StreamId
-  -> Chan (StreamId, Chan (FrameHeader, Either e0 FramePayload), StreamId)
-  -> IO (StreamId, Chan (FrameHeader, Either e0 FramePayload), StreamId)
+  -> PushPromisesChan e
+  -> IO (PushPromisesChanContent e)
 waitPushPromiseWithParentStreamId sid chan =
     loop
   where
     loop = do
-        tuple@(parentSid,_,_) <- readChan chan
+        tuple@(parentSid,_,_,_,_) <- readChan chan
         if parentSid == sid
         then return tuple
         else loop
