diff --git a/Phys/FunctorCore/include/Functors/PID.h b/Phys/FunctorCore/include/Functors/PID.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c74eca3dcc94f17f632ee5e594280c3ae1c741a
--- /dev/null
+++ b/Phys/FunctorCore/include/Functors/PID.h
@@ -0,0 +1,87 @@
+/*****************************************************************************\
+* (c) Copyright 2023 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.                                       *
+\*****************************************************************************/
+#pragma once
+#include "Event/ProtoParticle.h"
+#include "Functors/Function.h"
+#include "Kernel/RichParticleIDType.h"
+
+namespace Functors::PID {
+
+  namespace details {
+
+    LHCb::RichPID const* getRichPID( LHCb::Particle const& p ) {
+      auto const* proto = p.proto();
+      return proto ? proto->richPID() : nullptr;
+    }
+
+  } // namespace details
+
+  template <Rich::ParticleIDType pidtype, bool scaled = false>
+  struct RichDLL : public Function {
+    auto operator()( LHCb::Particle const& p ) const {
+      auto const* pid = details::getRichPID( p );
+      if constexpr ( scaled ) {
+        return pid ? Functors::Optional{pid->scaledDLLForCombDLL( pidtype )} : std::nullopt;
+      } else {
+        return pid ? Functors::Optional{pid->particleDeltaLL( pidtype )} : std::nullopt;
+      }
+    }
+
+    auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); }
+  };
+
+  using RichDLLe  = RichDLL<Rich::ParticleIDType::Electron>;
+  using RichDLLmu = RichDLL<Rich::ParticleIDType::Muon>;
+  using RichDLLp  = RichDLL<Rich::ParticleIDType::Proton>;
+  using RichDLLk  = RichDLL<Rich::ParticleIDType::Kaon>;
+  using RichDLLpi = RichDLL<Rich::ParticleIDType::Pion>;
+  using RichDLLd  = RichDLL<Rich::ParticleIDType::Deuteron>;
+  using RichDLLbt = RichDLL<Rich::ParticleIDType::BelowThreshold>;
+
+  using RichScaledDLLe  = RichDLL<Rich::ParticleIDType::Electron, true>;
+  using RichScaledDLLmu = RichDLL<Rich::ParticleIDType::Muon, true>;
+
+  struct Rich1GasUsed : public Predicate {
+    bool operator()( LHCb::Particle const& p ) const {
+      auto const* pid = details::getRichPID( p );
+      return pid ? pid->usedRich1Gas() : false;
+    }
+
+    auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); }
+  };
+
+  struct Rich2GasUsed : public Predicate {
+    bool operator()( LHCb::Particle const& p ) const {
+      auto const* pid = details::getRichPID( p );
+      return pid ? pid->usedRich2Gas() : false;
+    }
+
+    auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); }
+  };
+
+  template <Rich::ParticleIDType pidtype>
+  struct RichThreshold : public Predicate {
+    bool operator()( LHCb::Particle const& p ) const {
+      auto const* pid = details::getRichPID( p );
+      return pid ? pid->isAboveThreshold( pidtype ) : false;
+    }
+
+    auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); }
+  };
+
+  using RichThresholdEl = RichThreshold<Rich::ParticleIDType::Electron>;
+  using RichThresholdKa = RichThreshold<Rich::ParticleIDType::Kaon>;
+  using RichThresholdMu = RichThreshold<Rich::ParticleIDType::Muon>;
+  using RichThresholdPi = RichThreshold<Rich::ParticleIDType::Pion>;
+  using RichThresholdPr = RichThreshold<Rich::ParticleIDType::Proton>;
+  using RichThresholdDe = RichThreshold<Rich::ParticleIDType::Deuteron>;
+
+} // namespace Functors::PID
diff --git a/Phys/FunctorCore/include/Functors/Particle.h b/Phys/FunctorCore/include/Functors/Particle.h
index 8713c88e97986a6738c8f0f1781602162e63a02b..2e93e529f4b47d56db9cb81ffb25a183d85c9875 100644
--- a/Phys/FunctorCore/include/Functors/Particle.h
+++ b/Phys/FunctorCore/include/Functors/Particle.h
@@ -195,9 +195,13 @@ namespace Functors::Particle {
     bool operator()( LHCb::ProtoParticle const* pp ) const { return pp && ( *this )( *pp ); }
   };
 
-  using PPHasRich     = PPHasInfo<LHCb::ProtoParticle::RichPIDStatus>;
   using PPHasMuonInfo = PPHasInfo<LHCb::ProtoParticle::InAccMuon>;
 
+  struct PPHasRich : Predicate {
+    bool operator()( LHCb::ProtoParticle const& pp ) const { return pp.richPID(); }
+    bool operator()( LHCb::ProtoParticle const* pp ) const { return pp && ( *this )( *pp ); }
+  };
+
   struct PPHasEcalInfo : public Predicate {
     bool operator()( LHCb::ProtoParticle const& pp ) const {
       constexpr auto ecal_info = std::array{
diff --git a/Phys/FunctorCore/include/Functors/TrackLike.h b/Phys/FunctorCore/include/Functors/TrackLike.h
index ea3c1d59a938b377aafe70aba59a23e053c77861..d8c561db216ff81025e5d7771d8962a27a32bc25 100644
--- a/Phys/FunctorCore/include/Functors/TrackLike.h
+++ b/Phys/FunctorCore/include/Functors/TrackLike.h
@@ -407,16 +407,6 @@ namespace Functors::Track {
         return d.HcalPIDe();
       case additInfo::HcalPIDmu:
         return d.HcalPIDmu();
-      case additInfo::RichDLLp:
-        return d.RichDLLp();
-      case additInfo::RichDLLk:
-        return d.RichDLLk();
-      case additInfo::RichDLLpi:
-        return d.RichDLLpi();
-      case additInfo::RichDLLd:
-        return d.RichDLLd();
-      case additInfo::RichDLLbt:
-        return d.RichDLLbt();
       case additInfo::CaloEoverP:
         return d.ElectronShowerEoP();
       case additInfo::ElectronShowerDLL:
@@ -450,13 +440,6 @@ namespace Functors::Track {
   using EcalPIDmu            = NumAdditionalInfo<additInfo::EcalPIDmu>;
   using HcalPIDe             = NumAdditionalInfo<additInfo::HcalPIDe>;
   using HcalPIDmu            = NumAdditionalInfo<additInfo::HcalPIDmu>;
-  using RichDLLe             = NumAdditionalInfo<additInfo::RichDLLe>;
-  using RichDLLmu            = NumAdditionalInfo<additInfo::RichDLLmu>;
-  using RichDLLp             = NumAdditionalInfo<additInfo::RichDLLp>;
-  using RichDLLk             = NumAdditionalInfo<additInfo::RichDLLk>;
-  using RichDLLpi            = NumAdditionalInfo<additInfo::RichDLLpi>;
-  using RichDLLd             = NumAdditionalInfo<additInfo::RichDLLd>;
-  using RichDLLbt            = NumAdditionalInfo<additInfo::RichDLLbt>;
   using ElectronShowerEoP    = NumAdditionalInfo<additInfo::CaloEoverP>;
   using ElectronShowerDLL    = NumAdditionalInfo<additInfo::ElectronShowerDLL>;
   using ClusterMatch         = NumAdditionalInfo<additInfo::CaloTrMatch>;
diff --git a/Phys/FunctorCore/python/Functors/__init__.py b/Phys/FunctorCore/python/Functors/__init__.py
index ee5e0ec89a005afb98fa06f863849578bb89cf3f..eede027924abd875e39e366b43a03a71c54029f2 100644
--- a/Phys/FunctorCore/python/Functors/__init__.py
+++ b/Phys/FunctorCore/python/Functors/__init__.py
@@ -798,33 +798,80 @@ HCALPIDMU = Functor(
 
                     Functor's call operator expects a track like object.""")
 RICH_DLL_E = Functor(
-    'RICH_DLL_E', "Track::RichDLLe", """Rich-based DLL for electron-ID.
+    'RICH_DLL_E', "PID::RichDLLe", """Rich-based DLL for electron-ID.
 
                    Functor's call operator expects a track like object.""")
 RICH_DLL_MU = Functor(
-    'RICH_DLL_MU', "Track::RichDLLmu", """Rich-based DLL for mu-ID.
+    'RICH_DLL_MU', "PID::RichDLLmu", """Rich-based DLL for mu-ID.
 
                     Functor's call operator expects a track like object.""")
 RICH_DLL_P = Functor(
-    'RICH_DLL_P', "Track::RichDLLp", """Rich-based DLL for proton-ID.
+    'RICH_DLL_P', "PID::RichDLLp", """Rich-based DLL for proton-ID.
 
                    Functor's call operator expects a track like object.""")
 RICH_DLL_K = Functor(
-    'RICH_DLL_K', "Track::RichDLLk", """Rich-based DLL for kaon-ID.
+    'RICH_DLL_K', "PID::RichDLLk", """Rich-based DLL for kaon-ID.
 
                     Functor's call operator expects a track like object.""")
 RICH_DLL_PI = Functor(
-    'RICH_DLL_PI', "Track::RichDLLpi", """Rich-based DLL for pion-ID.
+    'RICH_DLL_PI', "PID::RichDLLpi", """Rich-based DLL for pion-ID.
 
                     Functor's call operator expects a track like object.""")
 RICH_DLL_D = Functor(
-    'RICH_DLL_D', "Track::RichDLLd", """Rich-based DLL for deuteron-ID.
+    'RICH_DLL_D', "PID::RichDLLd", """Rich-based DLL for deuteron-ID.
 
                     Functor's call operator expects a track like object.""")
 RICH_DLL_BT = Functor(
-    'RICH_DLL_BT', "Track::RichDLLbt",
+    'RICH_DLL_BT', "PID::RichDLLbt",
     """Rich-based DLL for below threshold tracks.
 
+                    Functor's call operator expects a track like object.""")
+RICH_SCALED_DLL_E = Functor(
+    'RICH_SCALED_DLL_E', "PID::RichScaledDLLe",
+    """Rich-based DLL for electron-ID.
+    Scaled with monotonic function to approximate true DLL.
+    For usage in combined DLLs (with other subdetectors).
+
+    Functor's call operator expects a track like object.""")
+RICH_SCALED_DLL_MU = Functor(
+    'RICH_SCALED_DLL_MU', "PID::RichScaledDLLmu", """Rich-based DLL for mu-ID.
+    Scaled with monotonic function to approximate true DLL.
+    For usage in combined DLLs (with other subdetectors).
+
+    Functor's call operator expects a track like object.""")
+RICH1_GAS_USED = Functor(
+    'RICH1_GAS_USED', "PID::Rich1GasUsed", """Rich 1 gas flag.
+
+                    Functor's call operator expects a track like object.""")
+RICH2_GAS_USED = Functor(
+    'RICH2_GAS_USED', "PID::Rich2GasUsed", """Rich 2 gas flag.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_EL = Functor(
+    'RICH_THRESHOLD_EL', "PID::RichThresholdEl",
+    """Rich threshold for electrons.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_KA = Functor(
+    'RICH_THRESHOLD_KA', "PID::RichThresholdKa", """Rich threshold for kaons.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_MU = Functor(
+    'RICH_THRESHOLD_MU', "PID::RichThresholdMu", """Rich threshold for muons.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_PI = Functor(
+    'RICH_THRESHOLD_PI', "PID::RichThresholdPi", """Rich threshold for pions.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_PR = Functor(
+    'RICH_THRESHOLD_PR', "PID::RichThresholdPr", """Rich threshold for protons.
+
+                    Functor's call operator expects a track like object.""")
+RICH_THRESHOLD_DE = Functor(
+    'RICH_THRESHOLD_DE', "PID::RichThresholdDe",
+    """Rich threshold for deuterons.
+
                     Functor's call operator expects a track like object.""")
 ELECTRONSHOWEREOP = Functor(
     'ELECTRONSHOWEREOP', "Track::ElectronShowerEoP",
diff --git a/Phys/FunctorCore/tests/options/test_functors_tested.py b/Phys/FunctorCore/tests/options/test_functors_tested.py
index 8348dc2dbd572ad5ba6d94e0a5c1ed4d165b8534..3b15d3783429c9a60cfd3720cb81687b29a5abc3 100644
--- a/Phys/FunctorCore/tests/options/test_functors_tested.py
+++ b/Phys/FunctorCore/tests/options/test_functors_tested.py
@@ -80,7 +80,10 @@ exceptions = [
     'Functors::Particle::GetProtoParticle',
     'Functors::Adapters::GenerationFromCompositeV1( /* The generation of the children. Generation 1 are direct children, Generation 2 are grandchildren and so on. */ std::integral_constant<int, 1>{}',
     'Functors::Adapters::GenerationFromCompositeV1( /* The generation of the children. Generation 1 are direct children, Generation 2 are grandchildren and so on. */ std::integral_constant<int, 2>{}',
-    'Functors::Particle::ParticlePropertyUser'
+    'Functors::Particle::ParticlePropertyUser',
+    'Functors::PID::RichThresholdDe', 'Functors::PID::RichThresholdKa',
+    'Functors::PID::RichThresholdMu', 'Functors::PID::RichThresholdPi',
+    'Functors::PID::RichThresholdPr'
 ]
 
 functor_cpp_names = []
diff --git a/Phys/FunctorCore/tests/src/TestFunctors.cpp b/Phys/FunctorCore/tests/src/TestFunctors.cpp
index 2edcb7b3593d9a318563c3235877179ae979439d..0f0316f6f4bc08cb3be2156cc3d73cb036c58d50 100644
--- a/Phys/FunctorCore/tests/src/TestFunctors.cpp
+++ b/Phys/FunctorCore/tests/src/TestFunctors.cpp
@@ -33,6 +33,7 @@
 #include "Functors/JIT_includes.h"
 #include "Functors/MVA.h"
 #include "Functors/NeutralLike.h"
+#include "Functors/PID.h"
 #include "Functors/Particle.h"
 #include "Functors/Simulation.h"
 #include "Functors/TES.h"
@@ -216,55 +217,40 @@ BOOST_AUTO_TEST_CASE( test_rich_dll ) {
   double true_val = 0.3;
 
   // get functors
-  auto const RICH_DLL_E  = Functors::Track::RichDLLe{};
-  auto const RICH_DLL_K  = Functors::Track::RichDLLk{};
-  auto const RICH_DLL_PI = Functors::Track::RichDLLpi{};
-  auto const RICH_DLL_P  = Functors::Track::RichDLLp{};
-  auto const RICH_DLL_MU = Functors::Track::RichDLLmu{};
-  auto const RICH_DLL_D  = Functors::Track::RichDLLd{};
-  auto const RICH_DLL_BT = Functors::Track::RichDLLbt{};
-
-  // define particles
-  auto e  = LHCb::Particle( LHCb::ParticleID{11} );
-  auto k  = LHCb::Particle( LHCb::ParticleID{321} );
-  auto pi = LHCb::Particle( LHCb::ParticleID{-211} );
-  auto p  = LHCb::Particle( LHCb::ParticleID{2212} );
-  auto mu = LHCb::Particle( LHCb::ParticleID{-13} );
-  auto d  = LHCb::Particle( LHCb::ParticleID{1000010020} );
-
-  // define proto particles
-  auto e_proto  = LHCb::ProtoParticle();
-  auto k_proto  = LHCb::ProtoParticle();
-  auto pi_proto = LHCb::ProtoParticle();
-  auto p_proto  = LHCb::ProtoParticle();
-  auto mu_proto = LHCb::ProtoParticle();
-  auto d_proto  = LHCb::ProtoParticle();
+  auto const RICH_DLL_E  = Functors::PID::RichDLLe{};
+  auto const RICH_DLL_K  = Functors::PID::RichDLLk{};
+  auto const RICH_DLL_PI = Functors::PID::RichDLLpi{};
+  auto const RICH_DLL_P  = Functors::PID::RichDLLp{};
+  auto const RICH_DLL_MU = Functors::PID::RichDLLmu{};
+  auto const RICH_DLL_D  = Functors::PID::RichDLLd{};
+  auto const RICH_DLL_BT = Functors::PID::RichDLLbt{};
+
+  // define particle and protoparticle
+  auto part  = LHCb::Particle( LHCb::ParticleID{11} );
+  auto proto = LHCb::ProtoParticle();
 
   // add DLL info
-  e_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLe, true_val );
-  k_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLk, true_val );
-  pi_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLpi, true_val );
-  p_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLp, true_val );
-  mu_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLmu, true_val );
-  d_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLd, true_val );
-  d_proto.addInfo( LHCb::ProtoParticle::additionalInfo::RichDLLbt, true_val );
-
-  // set proto in particles
-  e.setProto( &e_proto );
-  k.setProto( &k_proto );
-  pi.setProto( &pi_proto );
-  p.setProto( &p_proto );
-  mu.setProto( &mu_proto );
-  d.setProto( &d_proto );
+  auto pid = LHCb::RichPID();
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Electron, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Muon, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Pion, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Kaon, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Proton, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::Deuteron, true_val );
+  pid.setParticleDeltaLL( Rich::ParticleIDType::BelowThreshold, true_val );
+
+  // add info
+  proto.setRichPID( &pid );
+  part.setProto( &proto );
 
   // do checks
-  BOOST_CHECK( RICH_DLL_E( e ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_K( k ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_PI( pi ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_P( p ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_MU( mu ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_D( d ).value_or( true_val + 1 ) - true_val < 1e-6 );
-  BOOST_CHECK( RICH_DLL_BT( d ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_E( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_K( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_PI( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_P( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_MU( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_D( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
+  BOOST_CHECK( RICH_DLL_BT( part ).value_or( true_val + 1 ) - true_val < 1e-6 );
 }
 
 // check we can apply an IsMuon cut to some tracks
@@ -417,10 +403,13 @@ BOOST_AUTO_TEST_CASE( test_ai_functors ) {
                             ( Functors::Track::ElectronEnergy{} > 0.f ) & ( Functors::Track::BremHypoEnergy{} > 0.f ) &
                             ( Functors::Track::BremHypoDeltaX{} > 0.f ) & ( Functors::Track::BremHypoID{} > 0 ) &
                             ( Functors::Track::BremTrackBasedEnergy{} > 0.f ) & ( Functors::Track::ElectronID{} > 0 ) &
-                            ( Functors::Track::HcalEoP{} > 0.f ) & ( Functors::Track::RichDLLe{} > 0.f ) &
-                            ( Functors::Track::RichDLLmu{} > 0.f ) & ( Functors::Track::RichDLLp{} > 0.f ) &
-                            ( Functors::Track::RichDLLk{} > 0.f ) & ( Functors::Track::RichDLLpi{} > 0.f ) &
-                            ( Functors::Track::RichDLLd{} > 0.f ) & ( Functors::Track::RichDLLbt{} > 0.f ) );
+                            ( Functors::Track::HcalEoP{} > 0.f ) & ( Functors::PID::RichDLLe{} > 0.f ) &
+                            ( Functors::PID::RichDLLmu{} > 0.f ) & ( Functors::PID::RichDLLp{} > 0.f ) &
+                            ( Functors::PID::RichDLLk{} > 0.f ) & ( Functors::PID::RichDLLpi{} > 0.f ) &
+                            ( Functors::PID::RichDLLd{} > 0.f ) & ( Functors::PID::RichDLLbt{} > 0.f ) &
+                            ( Functors::PID::RichScaledDLLe{} > 0.f ) & ( Functors::PID::RichScaledDLLmu{} > 0.f ) &
+                            ( Functors::PID::RichThresholdEl{} ) & ( Functors::PID::Rich1GasUsed{} ) &
+                            ( Functors::PID::Rich2GasUsed{} ) );
 }
 
 BOOST_AUTO_TEST_CASE( test_1trackmva_functor ) {
diff --git a/Phys/ProtoParticleFilter/src/ProtoParticleSelection.h b/Phys/ProtoParticleFilter/src/ProtoParticleSelection.h
index 1c21927f227d87d1429c88ba32f4d3e87d611884..27b56b24142ab5be07713266b35bdd89055ddaf0 100644
--- a/Phys/ProtoParticleFilter/src/ProtoParticleSelection.h
+++ b/Phys/ProtoParticleFilter/src/ProtoParticleSelection.h
@@ -402,9 +402,7 @@ public: // Helper classes
     // Methods to test if a ProtoParticle has any sub-det DLL information
 
     /// Does this ProtoParticle have RICH DLL information
-    inline bool hasRichDLL( const LHCb::ProtoParticle* proto ) const {
-      return proto->hasInfo( LHCb::ProtoParticle::additionalInfo::RichPIDStatus );
-    }
+    inline bool hasRichDLL( const LHCb::ProtoParticle* proto ) const { return proto->richPID(); }
 
     /// Does this ProtoParticle have MUON DLL information
     inline bool hasMuonDLL( const LHCb::ProtoParticle* proto ) const {