Here is the best way to move/shift references in a formula, and it uses the function ConvertFormula()!
Function MoveFormulaReferences$(strFormula$, rngRelativeTo As Range, lngOffsetRows&, lngOffsetColumns)
MoveFormulaReferences = Application.ConvertFormula( _
Application.ConvertFormula( _
strFormula, _
XlReferenceStyle.xlA1, _
XlReferenceStyle.xlR1C1, _
, _
rngRelativeTo), _
XlReferenceStyle.xlR1C1, _
XlReferenceStyle.xlA1, _
, _
rngRelativeTo.Offset(lngOffsetRows, lngOffsetColumns))
End Function
Now some examples:
?MoveFormulaReferences("=C3*2+C3", Range("$D$4"), -2, -2)
returns =A1*2+A1
?MoveFormulaReferences("=$C3*2+C3", Range("$D$4"), -2, -2)
returns =$C1*2+A1
It is also possible to "force-move" all references, even the ones made absolute by a leading $, using the ToAbsolute parameter of the ConvertFormula() function: pass XlReferenceType.xlRelative as argument in the nested ConvertFormula() call
Edit:
One could argue the use of the rngRelativeTo parameter: it appears it can be confounding... At first I thought that the above behaves exactly as if a cell containing the formula was moved, but @GSerg, in its own way, made me realize that is not entirely correct, here an example:

If cell C1 is copied and pasted in B1, the A1 reference in the formula being moved becomes #REF!. I expected my function with ConvertFormula() to have the same behavior than Excel's copy/paste but in fact, it "rotates the references from start to end" instead of "blocking" them when out of boundaries:
?MoveFormulaReferences("=A1*2", Range("C1"), 0, -2)
returns =XFC1*2
So one might think the rngRelativeTo parameter is useless in that case since it does not prevent the "blocking", and that internally it could be replaced by Range("A1") as a proxy, but it is incorrect: considering the same example: Range("A1").Offset(0, -2) cannot be resolved. In the end, a user-provided relative range is required to simulate a real scenario.
Range("A1") would work if both offsets are >= 0
Range("XFD1048576") would work if both offsets are <= 0
No single Range would work in any feasible case where one offset is > 0 and the other < 0, so rngRelativeTo is required to simulate a real copy/paste situation.
Edit 2:
Here is a function whose usage might be a little more intuitive for the op particular situation (still not using a copy/paste operation):
Function MoveCellFormulaReferences$(rngCell, lngOffsetRows&, lngOffsetColumns&)
MoveCellFormulaReferences$ = Application.ConvertFormula( _
Application.ConvertFormula( _
rngCell.Formula, _
XlReferenceStyle.xlA1, _
XlReferenceStyle.xlR1C1, _
, _
rngCell), _
XlReferenceStyle.xlR1C1, _
XlReferenceStyle.xlA1, _
, _
rngCell.Offset(lngOffsetRows, lngOffsetColumns))
End Function
EDIT 3:
and even, reduced to its simplest form:
Function MoveCellFormulaReferences2$(rngCell, lngOffsetRows&, lngOffsetColumns&)
MoveCellFormulaReferences2$ = Application.ConvertFormula( _
rngCell.FormulaR1C1, _
XlReferenceStyle.xlR1C1, _
XlReferenceStyle.xlA1, _
, _
rngCell.Offset(lngOffsetRows, lngOffsetColumns))
End Function
But the first version works with any String A1 formula, it does not suppose you have a cell holding the R1C1 translation or that you want to use a temp cell to translate it...
I don't know how to quickly prevent the "rotation" though, other than analyzing the formula string, but that defeats the purpose of my answer...