diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,16 @@
+## Version 2023.2
+
+- Add support for PAYG Instalments, which are specified in aggregate
+  as a refundable tax offset via the `paygInstalments` field.
+
+- Add the `Deductions` type, which expresses the various deduction
+  types, as well as the (aggregate) amount of deductions related to
+  foreign income.
+
+- Implement the Foreign Income Tax Offset Limit.  The limit will be
+  calculated and the `foreignTaxOffset` field in the `TaxReturnInfo`
+  will be clamped to it.
+
+## Older versions
+
+See Git commit history
diff --git a/src/Data/Tax/ATO.hs b/src/Data/Tax/ATO.hs
--- a/src/Data/Tax/ATO.hs
+++ b/src/Data/Tax/ATO.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE PolyKinds #-}
+
 -- This file is part of hs-tax-ato
 -- Copyright (C) 2018-2021  Fraser Tweedale
 --
@@ -96,13 +98,32 @@
   , dependentChildren
 
   -- ** Deductions
+  , Deductions
+  , deductions
+  , totalDeductions
+  , workRelatedCarExpenses
+  , workRelatedTravelExpenses
+  , workRelatedClothingLaundryAndDryCleaningExpenses
+  , workRelatedSelfEducationExpenses
+  , otherWorkRelatedExpenses
+  , lowValuePoolDeduction
+  , interestDeductions
+  , dividendDeductions
+  , giftsOrDonations
+  , costOfManagingTaxAffairs
+  , deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity
+  , personalSuperannuationContributions
+  , deductionForProjectPool
+  , forestryManagedInvestmentSchemeDeduction
+  , otherDeductions
+  , foreignIncomeDeductions
 
   -- ** Tax offsets
-  , deductions
   , Offsets
   , offsets
   , spouseContributionOffset
   , foreignTaxOffset
+  , paygInstalments
 
   -- ** Assessing tax
   , TaxAssessment
@@ -128,7 +149,7 @@
   , module Data.Tax.ATO.Rounding
   ) where
 
-import Control.Lens (Getter, Lens', foldOf, lens, to, view)
+import Control.Lens (Getter, Lens', (&), foldOf, lens, set, to, view, views)
 
 import Data.Tax
 import Data.Tax.ATO.CGT
@@ -234,7 +255,7 @@
   , _ess :: ESSStatement a
   , _foreignIncome :: Money a
   , _cgtEvents :: [CGTEvent a]
-  , _deductions :: Money a
+  , _deductions :: Deductions a
   , _offsets :: Offsets a
   , _triCapitalLossCarryForward :: Money a
   , _phi :: [PrivateHealthInsurancePolicyDetail a]
@@ -310,7 +331,7 @@
 cgtEvents :: Lens' (TaxReturnInfo y a) [CGTEvent a]
 cgtEvents = lens _cgtEvents (\s b -> s { _cgtEvents = b })
 
-deductions :: Lens' (TaxReturnInfo y a) (Money a)
+deductions :: Lens' (TaxReturnInfo y a) (Deductions a)
 deductions = lens _deductions (\s b -> s { _deductions = b })
 
 offsets :: Lens' (TaxReturnInfo y a) (Offsets a)
@@ -377,18 +398,24 @@
 
 -- | Consolidated individual tax rate incorporating
 -- HELP and SFSS repayments
--- (if applicable) and automatic offsets (e.g. LITO).
+-- (if applicable) and automatic offsets (e.g. LITO, LMITO).
 individualTax
   :: (Fractional a, Ord a)
   => TaxTables y a
+  -> Tax (Money a) (Money a)
+individualTax table =
+  greaterOf mempty (ttIndividualIncomeTax table <> ttAdditional table)
+
+-- | Tax to calculate compulsory study and training loan repayments
+-- (e.g. HELP, SFSS)
+studyAndTrainingLoanRepayment
+  :: (Fractional a, Ord a)
+  => TaxTables y a
   -> TaxReturnInfo y a
   -> Tax (Money a) (Money a)
-individualTax table info =
-    greaterOf mempty $
-      ttIndividualIncomeTax table
-      <> limit (view helpBalance info) (ttHelp table)
-      <> limit (view sfssBalance info) (ttSfss table)
-      <> ttAdditional table
+studyAndTrainingLoanRepayment table info =
+  limit (view helpBalance info) (ttHelp table)
+  <> limit (view sfssBalance info) (ttSfss table)
 
 -- | Medicare levy + surcharge
 medicareLevyTax
@@ -422,7 +449,7 @@
         , view foreignIncome info
         ]
     in
-      wholeDollars (gross $-$ view deductions info)
+      wholeDollars (gross $-$ views deductions totalDeductions info)
 
 instance (Num a) => HasTaxWithheld (TaxReturnInfo y) a a where
   taxWithheld = to $ \info ->
@@ -438,7 +465,9 @@
     cg = assessCGTEvents
           (view capitalLossCarryForward info) (view cgtEvents info)
     taxable = view income info
-    due = getTax (individualTax tables info) taxable
+    due = getTax (individualTax tables) taxable
+    studyRepayment = getTax (studyAndTrainingLoanRepayment tables info) taxable
+    mlAndMLS = getTax (medicareLevyTax tables info) taxable
 
     incomeForSurchargePurposes =
       taxable
@@ -456,17 +485,34 @@
       (ttPHIRebateRates tables)
       (view privateHealthInsurancePolicyDetails info)
 
+    foreignIncomeTaxOffsetLimit =
+      let
+        step1 = due <> mlAndMLS
+        step2 =
+          let
+            info' = info & set foreignIncome mempty
+            taxable' = view income info' <> view (deductions . foreignIncomeDeductions) info'
+            due' = getTax (individualTax tables) taxable'
+            mlAndMLS' = getTax (medicareLevyTax tables info') taxable'
+          in
+            due' <> mlAndMLS'
+        step3 = step1 $-$ step2
+      in
+        max (Money 1000) step3
+
     frankingCredit =
       wholeDollars
       $ foldMap dividendFrankingCredit (view dividends info)
     off =
       view (offsets . spouseContributionOffset) info
-      <> view (offsets . foreignTaxOffset) info
+      <> min (view (offsets . foreignTaxOffset) info) foreignIncomeTaxOffsetLimit
+      <> view (offsets . paygInstalments) info
+
   in
     TaxAssessment
       taxable
-      due
-      (getTax (medicareLevyTax tables info) taxable)
+      (due <> studyRepayment)
+      mlAndMLS
       (view taxWithheld info)
       (frankingCredit <> off)
       cg
@@ -475,7 +521,7 @@
 -- | Australian Business Number
 type ABN = String
 
--- | PAYG payment summary
+-- | PAYG payment summary - individual non-business
 data PaymentSummary a = PaymentSummary
   { summaryABN :: ABN
   , summaryGross :: Money a
@@ -531,16 +577,28 @@
     <> view taxWithheld d
 
 -- | Tax offsets that individuals can claim
+--
+-- The following lenses are available:
+--
+-- +---------------------------------------+----------------------------------+
+-- | 'spouseContributionOffset'            | Spouse super contribution        |
+-- +---------------------------------------+----------------------------------+
+-- | 'foreignTaxOffset'                    | Foreign income tax offset        |
+-- +---------------------------------------+----------------------------------+
+-- | 'paygInstalments'                     | PAYG Instalments                 |
+-- +---------------------------------------+----------------------------------+
+--
 data Offsets a = Offsets
   { _spouseOffset :: Money a
   , _foreignTaxOffset :: Money a
+  , _paygInstalments :: Money a
   }
 
 instance Num a => Semigroup (Offsets a) where
-  Offsets a b <> Offsets a' b' = Offsets (a <> a') (b <> b')
+  Offsets a b c <> Offsets a' b' c' = Offsets (a <> a') (b <> b') (c <> c')
 
 instance Num a => Monoid (Offsets a) where
-  mempty = Offsets mempty mempty
+  mempty = Offsets mempty mempty mempty
   mappend = (<>)
 
 -- | Spouse contribution offset.  Maximum of /$540/ (not enforced).
@@ -550,6 +608,165 @@
 -- | Offset for tax paid on foreign income.
 foreignTaxOffset :: Lens' (Offsets a) (Money a)
 foreignTaxOffset = lens _foreignTaxOffset (\s b -> s { _foreignTaxOffset = b })
+
+paygInstalments :: Lens' (Offsets a) (Money a)
+paygInstalments = lens _paygInstalments (\s b -> s { _paygInstalments = b })
+
+
+-- | Deductions that individuals can claim.
+--
+-- The only "special case" field is 'foreignIncomeDeductions', which is
+-- the aggregate amount of /other/ deductions that pertains to foreign
+-- income.  It is used only for calculating the Foreign Income Tax Offset
+-- Limit.
+--
+data Deductions a = Deductions
+  { _workRelatedCarExpenses :: Money a
+  , _workRelatedTravelExpenses :: Money a
+  , _workRelatedClothingLaundryAndDryCleaningExpenses :: Money a
+  , _workRelatedSelfEducationExpenses :: Money a
+  , _otherWorkRelatedExpenses :: Money a
+  , _lowValuePoolDeduction :: Money a
+  , _interestDeductions :: Money a
+  , _dividendDeductions :: Money a
+  , _giftsOrDonations :: Money a
+  , _costOfManagingTaxAffairs :: Money a
+  , _deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity :: Money a
+  , _personalSuperannuationContributions :: Money a
+  , _deductionForProjectPool :: Money a
+  , _forestryManagedInvestmentSchemeDeduction :: Money a
+  , _otherDeductions :: Money a
+  , _foreignIncomeDeductions :: Money a
+  }
+
+instance Num a => Semigroup (Deductions a) where
+  Deductions a b c d e f g h i j k l m n o p
+    <> Deductions a' b' c' d' e' f' g' h' i' j' k' l' m' n' o' p'
+      = Deductions (a <> a') (b <> b') (c <> c') (d <> d') (e <> e') (f <> f') (g <> g') (h <> h')
+                   (i <> i') (j <> j') (k <> k') (l <> l') (m <> m') (n <> n') (o <> o') (p <> p')
+
+instance Num a => Monoid (Deductions a) where
+  mempty = Deductions mempty mempty mempty mempty mempty mempty mempty mempty
+                      mempty mempty mempty mempty mempty mempty mempty mempty
+
+-- | Sum the deductions.  Negative components are ignored.
+totalDeductions :: (Num a, Ord a) => Deductions a -> Money a
+totalDeductions a =
+  foldMap (max mempty)
+    [ view workRelatedCarExpenses a
+    , view workRelatedTravelExpenses a
+    , view workRelatedClothingLaundryAndDryCleaningExpenses a
+    , view workRelatedSelfEducationExpenses a
+    , view otherWorkRelatedExpenses a
+    , view lowValuePoolDeduction a
+    , view interestDeductions a
+    , view dividendDeductions a
+    , view giftsOrDonations a
+    , view costOfManagingTaxAffairs a
+    , view deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity a
+    , view personalSuperannuationContributions a
+    , view deductionForProjectPool a
+    , view forestryManagedInvestmentSchemeDeduction a
+    , view otherDeductions a
+    ]
+
+-- | __D1__ Work-related car expenses
+workRelatedCarExpenses :: Lens' (Deductions a) (Money a)
+workRelatedCarExpenses =
+  lens _workRelatedCarExpenses (\s b -> s { _workRelatedCarExpenses = b })
+
+-- | __D2__ Work-related travel expenses
+workRelatedTravelExpenses :: Lens' (Deductions a) (Money a)
+workRelatedTravelExpenses =
+  lens _workRelatedTravelExpenses (\s b -> s { _workRelatedTravelExpenses = b })
+
+-- | __D3__ Work-related clothing, laundry and dry-cleaning expenses
+workRelatedClothingLaundryAndDryCleaningExpenses :: Lens' (Deductions a) (Money a)
+workRelatedClothingLaundryAndDryCleaningExpenses =
+  lens
+    _workRelatedClothingLaundryAndDryCleaningExpenses
+    (\s b -> s { _workRelatedClothingLaundryAndDryCleaningExpenses = b })
+
+-- | __D4__ Work-related self-education expenses
+workRelatedSelfEducationExpenses :: Lens' (Deductions a) (Money a)
+workRelatedSelfEducationExpenses =
+  lens _workRelatedSelfEducationExpenses (\s b -> s { _workRelatedSelfEducationExpenses = b })
+
+-- | __D5__ Other work-related expenses
+otherWorkRelatedExpenses :: Lens' (Deductions a) (Money a)
+otherWorkRelatedExpenses =
+  lens _otherWorkRelatedExpenses (\s b -> s { _otherWorkRelatedExpenses = b })
+
+-- | __D6__ Low-value pool deduction
+lowValuePoolDeduction :: Lens' (Deductions a) (Money a)
+lowValuePoolDeduction =
+  lens _lowValuePoolDeduction (\s b -> s { _lowValuePoolDeduction = b })
+
+-- | __D7__ Interest deductions
+interestDeductions :: Lens' (Deductions a) (Money a)
+interestDeductions =
+  lens _interestDeductions (\s b -> s { _interestDeductions = b })
+
+-- | __D8__ Dividend deductions
+dividendDeductions :: Lens' (Deductions a) (Money a)
+dividendDeductions =
+  lens _dividendDeductions (\s b -> s { _dividendDeductions = b })
+
+-- | __D9__ Gifts or donations
+giftsOrDonations :: Lens' (Deductions a) (Money a)
+giftsOrDonations =
+  lens _giftsOrDonations (\s b -> s { _giftsOrDonations = b })
+
+-- | __D10__ Cost of managing tax affairs
+costOfManagingTaxAffairs :: Lens' (Deductions a) (Money a)
+costOfManagingTaxAffairs =
+  lens _costOfManagingTaxAffairs (\s b -> s { _costOfManagingTaxAffairs = b })
+
+-- | __D11__ Deductible amount of undeducted purchase price of a foreign pension or annuity
+deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity :: Lens' (Deductions a) (Money a)
+deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity =
+  lens
+    _deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity 
+    (\s b -> s { _deductibleAmountOfUndeductedPurchasePriceOfAForeignPensionOrAnnuity = b })
+
+-- | __D12__ Personal superannuation contributions
+personalSuperannuationContributions :: Lens' (Deductions a) (Money a)
+personalSuperannuationContributions =
+  lens _personalSuperannuationContributions (\s b -> s { _personalSuperannuationContributions = b })
+
+-- | __D13__ Deduction for project pool
+deductionForProjectPool :: Lens' (Deductions a) (Money a)
+deductionForProjectPool =
+  lens _deductionForProjectPool (\s b -> s { _deductionForProjectPool = b })
+
+-- | __D14__ Forestry managed investment scheme deduction
+forestryManagedInvestmentSchemeDeduction :: Lens' (Deductions a) (Money a)
+forestryManagedInvestmentSchemeDeduction =
+  lens
+    _forestryManagedInvestmentSchemeDeduction
+    (\s b -> s { _forestryManagedInvestmentSchemeDeduction = b })
+
+-- | __D15__ Other deductions — not claimable at __D1__ to __D14__ or elsewhere
+-- in your tax return
+otherDeductions :: Lens' (Deductions a) (Money a)
+otherDeductions =
+  lens _otherDeductions (\s b -> s { _otherDeductions = b })
+
+-- | Aggregate of deductions related to foreign income, including:
+--
+-- * Deductions that are reasonably related to amounts on which foreign
+--   income tax has been paid
+-- * Debt deductions attributable to your overseas permanent establishment
+-- * Amount of the foreign loss component of one or more tax losses deducted
+--   in the income year.
+--
+-- The components making up this amount __must be included in other fields__.
+-- This field is only used in calculating the Foreign Income Tax Offset Limit.
+--
+foreignIncomeDeductions :: Lens' (Deductions a) (Money a)
+foreignIncomeDeductions =
+  lens _foreignIncomeDeductions (\s b -> s { _foreignIncomeDeductions = b })
+
 
 -- | A gross income (first argument) and amount of tax withheld (second argument)
 data GrossAndWithheld a = GrossAndWithheld (Money a) (Money a)
diff --git a/tax-ato.cabal b/tax-ato.cabal
--- a/tax-ato.cabal
+++ b/tax-ato.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                tax-ato
-version:             2023.1
+version:             2023.2
 synopsis:            Tax types and computations for Australia
 description:
   This library provides types and tax computations for tax
@@ -16,6 +16,7 @@
 build-type:          Simple
 tested-with:         GHC ==8.10.7 || ==9.0.2 || ==9.2.7 || ==9.4.4 || ==9.6.1
 extra-source-files:
+  CHANGELOG.md
   .hlint.yaml
 
 homepage:            https://github.com/frasertweedale/hs-tax-ato
