diff --git a/Hlt/HltDAQ/CMakeLists.txt b/Hlt/HltDAQ/CMakeLists.txt
index 4e4f326ff560616f93d41aeb22bb6e17a27befec..ca48b5ddc6030930b9cd4cd16a6bcf558ffdf5ac 100644
--- a/Hlt/HltDAQ/CMakeLists.txt
+++ b/Hlt/HltDAQ/CMakeLists.txt
@@ -20,6 +20,7 @@ gaudi_add_module(HltDAQ
         src/component/HltDecoderUtils.cpp
         src/component/HltDecReportsWriter.cpp
         src/component/HltDiffHltDecReports.cpp
+        src/component/HltLumiWriter.cpp
         src/component/HltPackedBufferWriter.cpp
         src/component/HltPackedBufferDecoder.cpp
         src/component/HltPackedBufferChecker.cpp
diff --git a/Hlt/HltDAQ/src/component/HltLumiWriter.cpp b/Hlt/HltDAQ/src/component/HltLumiWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..778f9e52aaaa1f0d1d67517e48e10f90697aad2e
--- /dev/null
+++ b/Hlt/HltDAQ/src/component/HltLumiWriter.cpp
@@ -0,0 +1,103 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2022 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+#include "Event/HltLumiSummary.h"
+#include "Event/RawEvent.h"
+#include "Kernel/IIndexedLumiSchemaSvc.h"
+#include "Kernel/STLExtensions.h"
+#include "LHCbAlgs/Transformer.h"
+
+//-----------------------------------------------------------------------------
+// Implementation file for class : HltLumiWriter
+//
+//-----------------------------------------------------------------------------
+
+/** @class HltLumiWriter HltLumiWriter.h
+ *  Fills the Raw Buffer banks for the LumiSummary
+ */
+class HltLumiWriter : public LHCb::Algorithm::Transformer<LHCb::RawBank::View( const LHCb::HltLumiSummary& )> {
+
+  DataObjectWriteHandle<LHCb::RawEvent> m_outputRawEvent{this, "RawEventLocation", LHCb::RawEventLocation::Default};
+  mutable Gaudi::Accumulators::AveragingCounter<> m_totDataSize{this, "Average event size / 32-bit words"};
+
+public:
+  HltLumiWriter( const std::string& name, ISvcLocator* pSvcLocator )
+      : Transformer{name, pSvcLocator, KeyValue{"InputBank", LHCb::HltLumiSummaryLocation::Default},
+                    KeyValue{"OutputBank", "DAQ/RawBanks/HltLumiSummary"}} {}
+
+  //=============================================================================
+  // Main execution
+  //  Fill the data bank, structure depends on encoding key
+  //=============================================================================
+  LHCb::RawBank::View operator()( const LHCb::HltLumiSummary& summary ) const override {
+    if ( summary.extraInfo().find( "encodingKey" ) == summary.extraInfo().end() ) {
+      throw std::runtime_error( "HltLumiSummary does not contain an encoding key" );
+    }
+    auto encodingKey = summary.extraInfo().at( "encodingKey" );
+    auto lumi_schema = m_svc->lumiCounters( encodingKey, 2 );
+
+    std::vector<unsigned int> bank;
+    bank.resize( lumi_schema.size / 4 );
+    for ( auto cntr : lumi_schema.counters ) {
+      if ( summary.extraInfo().find( cntr.name ) != summary.extraInfo().end() ) {
+        auto val = summary.extraInfo().at( cntr.name );
+        writeCounter( cntr.offset, cntr.size, &bank.front(), val );
+      } else {
+        warning() << "Field " << cntr.name << " ignored by lumiSummary schema " << encodingKey << endmsg;
+      }
+    }
+
+    auto rawEvent = m_outputRawEvent.getOrCreate();
+    if ( !rawEvent->banks( LHCb::RawBank::HltLumiSummary ).empty() ) {
+      throw std::runtime_error( "RawEvent already contains HltLumiSummary raw bank" );
+    }
+
+    // set source, type, version
+    rawEvent->addBank( 0, LHCb::RawBank::HltLumiSummary, 0, bank );
+
+    m_totDataSize += bank.size();
+
+    if ( msgLevel( MSG::DEBUG ) ) {
+      debug() << "Bank size: " << format( "%4d ", bank.size() ) << "Total Data bank size " << bank.size() << endmsg;
+    }
+
+    if ( msgLevel( MSG::VERBOSE ) ) {
+      verbose() << "DATA bank : " << endmsg;
+      for ( const auto& [k, w] : LHCb::range::enumerate( bank, 1 ) ) {
+        verbose() << format( " %8x %11d   ", w, w );
+        if ( k % 4 == 0 ) verbose() << endmsg;
+      }
+      verbose() << endmsg;
+    }
+
+    return rawEvent->banks( LHCb::RawBank::HltLumiSummary );
+  }
+
+  void writeCounter( unsigned offset, unsigned size, unsigned* target, unsigned value ) const {
+    // Check value fits within size bits
+    if ( size < ( 8 * sizeof( unsigned ) ) && value >= ( 1u << size ) ) { return; }
+
+    // Separate offset into a word part and bit part
+    unsigned word      = offset / ( 8 * sizeof( unsigned ) );
+    unsigned bitoffset = offset % ( 8 * sizeof( unsigned ) );
+
+    // Check size and offset line up with word boundaries
+    if ( bitoffset + size > ( 8 * sizeof( unsigned ) ) ) { return; }
+
+    // Apply the value to the matching bits
+    unsigned mask = ( ( 1 << size ) - 1 ) << bitoffset;
+    target[word]  = ( target[word] & ~mask ) | ( ( value << bitoffset ) & mask );
+  }
+
+private:
+  ServiceHandle<IIndexedLumiSchemaSvc> m_svc{this, "DecoderMapping", "HltANNSvc"};
+};
+
+DECLARE_COMPONENT( HltLumiWriter )